package org.piggy.core.context;

import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.util.ReferenceCountUtil;
import org.piggy.common.rule.Rule;
import org.piggy.core.reponse.GatewayResponse;
import org.piggy.core.request.GatewayRequest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

public class GatewayContext implements Context {

    protected Rule rule;

    protected GatewayRequest gatewayRequest;

    protected GatewayResponse gatewayResponse;

    protected String protocol;

    protected boolean gray;

    protected int status = Context.RUNNING;

    protected ChannelHandlerContext channelHandlerContext;

    protected Map<String, Object> attributes = new HashMap<>();

    protected Throwable throwable;

    protected boolean keepAlive;

    protected List<Consumer<Context>> terminatedCallbacks;

    public GatewayContext(String protocol, ChannelHandlerContext channelHandlerContext,
                          boolean keepAlive, GatewayRequest gatewayRequest, Rule rule) {
        this.protocol = protocol;
        this.channelHandlerContext = channelHandlerContext;
        this.keepAlive = keepAlive;
        this.gatewayRequest = gatewayRequest;
        this.rule = rule;
    }

    @Override
    public void running() {
        status = Context.RUNNING;
    }

    @Override
    public void written() {
        status = Context.WRITTEN;
    }

    @Override
    public void completed() {
        status = Context.COMPLETED;
    }

    @Override
    public void terminated() {
        status = Context.TERMINATED;
    }

    @Override
    public boolean isRunning() {
        return status == Context.RUNNING;
    }

    @Override
    public boolean isWritten() {
        return status == Context.WRITTEN;
    }

    @Override
    public boolean isCompleted() {
        return status == Context.COMPLETED;
    }

    @Override
    public boolean isTerminated() {
        return status == Context.TERMINATED;
    }

    @Override
    public boolean isKeepAlive() {
        return keepAlive;
    }

    @Override
    public String getProtocol() {
        return protocol;
    }

    @Override
    public GatewayRequest getGatewayRequest() {
        return gatewayRequest;
    }

    @Override
    public GatewayResponse getGatewayResponse() {
        return gatewayResponse;
    }

    @Override
    public Rule getRule() {
        return rule;
    }

    @Override
    public Throwable getThrowable() {
        return throwable;
    }

    @Override
    public ChannelHandlerContext getChannelHandlerContext() {
        return channelHandlerContext;
    }

    @Override
    public Object getAttribute(String key) {
        return attributes.get(key);
    }

    @Override
    public void setAttribute(String key, Object obj) {
        attributes.put(key,obj);
    }

    @Override
    public void releaseRequest() {
        FullHttpRequest fullHttpRequest = gatewayRequest.getFullHttpRequest();
        if(fullHttpRequest.refCnt() > 0){
            ReferenceCountUtil.release(fullHttpRequest);
        }
    }

    @Override
    public void setTerminatedCallBack(Consumer<Context> consumer) {
        if(terminatedCallbacks == null){
            terminatedCallbacks = new ArrayList<>();
        }
        terminatedCallbacks.add(consumer);
    }

    @Override
    public void invokeTerminatedCallBack() {
        if(terminatedCallbacks != null){
            terminatedCallbacks.forEach(consumer -> consumer.accept(this));
        }
    }

    public void setThrowable(Throwable throwable) {
        this.throwable = throwable;
    }

    public void setGatewayResponse(GatewayResponse gatewayResponse) {
        this.gatewayResponse = gatewayResponse;
    }

    public boolean isGray() {
        return gray;
    }

    public void setGray(boolean gray) {
        this.gray = gray;
    }
}
